#include "Texture.h"
#include "vender/stb_image/stb_image.h"


Texture::Texture(const std::string& path):m_RendererID(0), m_FilePath(path),
m_LocalBuffer(nullptr), m_Width(0), m_Height(0), m_BPP(0)
{
	// stb读取图片，默认读出来的数据排列顺序是：从图片左上角的点开始，右下角的点结束
	// 而OpenGL期待的点是从左下角开始,右上角结束的!
	stbi_set_flip_vertically_on_load(1);
	// 4 -> r g b a (看stb_image的注释)
	m_LocalBuffer = stbi_load(path.c_str(), &m_Width, &m_Height, &m_BPP, 4);
	
	GLCall(glGenTextures(1, &m_RendererID));
	GLCall(glBindTexture(GL_TEXTURE_2D, m_RendererID));

	// texture 四个参数必须设置，如果不设置只会看到黑色图
	GLCall(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR));	// 实际区域比texture小时的取样方式
	GLCall(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR));	// 实际区域比texture大时的取样方式
	GLCall(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE));
	GLCall(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE));

	// 再用glTexImage2D传输数据
	// param2: texture level!
	// param3: internal format是OpenGL内部如何存储数据的格式
	// param4~5: 宽和高
	// param6: format是我们提供的数据的格式
	// param7: 我们提供的数据的类型
	// param8: pointer
			// 可以不指定数据的指针,如果只是想申请GPU里的内存，数据指针传nullptr就是申请gpu的数据
			// 
	GLCall(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, m_Width, m_Height, 0, GL_RGBA, GL_UNSIGNED_BYTE, m_LocalBuffer));
	GLCall(glBindTexture(GL_TEXTURE_2D, 0));

	if (m_LocalBuffer)
	{
		// 在CPU这边保存数据也是常见的做法，因为我们可能需要对它做各种操作
		// 这里只是展示程序，所以用完就直接free掉cpu这边的数据了
		stbi_image_free(m_LocalBuffer);
	}
	
}

Texture::~Texture()
{
	GLCall(glDeleteTextures(1, &m_RendererID));
}

void Texture::Bind(unsigned slot) const
{
	// 因为我们点进去头文件看到 GL_TEXTURE0 到 GL_TEXTURE31的宏是连续的
	// 所以直接用 GL_TEXTURE0 + slot 表示第 slot 个 Texture 了
	// 讲道理应该把它们放到静态数组里
	// 绑定的时候，用glActiveTexture激活 某个贴图slot，再用 glBindTexture 绑定贴图
	GLCall(glActiveTexture(GL_TEXTURE0 + slot));
	GLCall(glBindTexture(GL_TEXTURE_2D, m_RendererID));
}

void Texture::Unbind() const
{
	GLCall(glBindTexture(GL_TEXTURE_2D, 0));
}
